/**
 * 本章节本没有什么重要的内容。
 * 但是也属于必须掌握的内容。这是因为现有的代码中有大量这样的写法，如果你不知道，那么阅读必须存在困难，相当影响速度。
 * 为了便于基于，有必要从两个方面进行强化
 * 1.复习书本上的例子
 * 2.把模式有关的内容绘制为一个脑图，并反复背诵
 *
 * 在这之前主要了解两个名词:
 * a.可反驳 -    refutable  
 *   对某些可能的值进行匹配会失败的模式被称为是 可反驳的（refutable）
 *   let Some(x) = some_option_value;如果 some_option_value 的值是 None，其不会成功匹配模式 Some(x)
 * b.不可反驳 -irrefutable
 *    能匹配任何传递的可能值的模式被称为是 不可反驳的（irrefutable）。
 *    一个例子就是 let x = 5; 语句中的 x，因为 x 可以匹配任何值所以不可能会失败
 */

struct Point {
    x: i32,
    y: i32,
}
#[allow(unused)]
enum Message {
    Quit,
    Move { x: i32, y: i32 },
    Write(String),
    ChangeColor(i32, i32, i32),
}
#[allow(unused)]
enum Color{
    Red,
    Green,
    OtherRgb(i32, i32, i32),
}
#[allow(unused)]
enum Work{
    Start,
    Stop,
    Pause(String),
    Cancel(Color),
    Finish
}
// 为了避免烦人的提示，直接在main函数上添加#[allow(unused)]注解，避免编译器提示未使用警告。
#[allow(unused)]
fn main() {
    //以下例子基本从书本上复制而来
    // 一、解构  -------------------------------------------------------------

    //1. match 匹配字面值。 这是匹配中最简单的
    let x = 1;
    match x {
        1 => println!(" x is 壹"),
        2 => println!(" x is 贰"),
        3 => println!(" x is 叁"),
        _ => println!(" x is 其它"),
    }

    //2. match匹配命名变量。 它的主要作用是捕获变量，以便打印或者他用
    let x = Some(5);
    let y = 10;
    match x {
        Some(50) => println!("Got 50"),
        Some(y) => println!("Matched, y = {y}"),
        _ => println!("Default case, x = {:?}", x),
    }

    //3. match 匹配多个值. 多个值可以用 | 分隔 .这是属于散列值匹配
    let x = 1;
    match x {
        1 | 2 => println!("小于3的正整数"),
        3 => println!("燕子三抄水"),
        _ => println!("不知所云...."),
    }

    //4. match 匹配区间值. 值区间使用..表示。 ..=表示区间匹配
    let x = 5;
    match x {
        1..=5 => println!("1-5之间的正整数"),
        _ => println!("其它"),
    }

    //5. 解构结构体  let语法. 还可以在主域中创建不在主域中定义的变量

    //凭空在主域创建变量 a,b。 按照其它语言的习惯，谁看了不迷茫！！！
    let p = Point { x: 0, y: 7 };
    let Point { x: a, y: b } = p;
    assert_eq!(0, a);
    assert_eq!(7, b);

    //和match枚举一样，也可以通过match捕获结构体的字段。
    //在match子域内部创建变量x,y（捕获）
    let p = Point { x: 99, y: 7 };
    match p {
        Point { x, y } => println!("坐标为({x},{y})"),
    }

    //6. 解构枚举，此类解构类似于match中解构结构体
    let msg = Message::ChangeColor(0, 160, 255);
    match msg {
        Message::Quit => {
            println!("The Quit variant has no data to destructure.");
        }
        Message::Move { x, y } => {
            println!("Move in the x direction {x} and in the y direction {y}");
        }
        Message::Write(text) => {
            println!("Text message: {text}");
        }
        Message::ChangeColor(r, g, b) => {
            println!("Change the color to red {r}, green {g}, and blue {b}")
        }
    }

    //7. 解构嵌套的结构体、枚举  -- 这个操作还是类似于利用match解构结构体
    let laugh=Work::Cancel(Color::OtherRgb(100,99,98));
    match laugh{
        Work::Cancel(Color::OtherRgb(r,g,b))=>{
            println!("r:{r},g:{g},b:{b}");
        }
        _=>{}
    }

    //8.解构结构体和元组  - 
    // 找不到理想的例子，用了书本上的.
    // 不太明白，这个算什么解构结构体和元组。 不如说解构元组吧
    let ((feet, inches), Point { x, y }) = ((3, 10), Point { x: 3, y: -10 });

    //来个解构元组的例子
    let tup = (1, 2, 3);
    let (a, b, c) = tup;
    println!("元组tmp中的三个值分别是-a:{a},b:{b},c:{c}");

    // 二.忽略  ------------------------------------------------------------------------
    
    //9.0 使用_忽略整个值 (方法或者函数的参数)
    ignore_test(92,202);
    
    //10. 使用嵌套的_忽略部分值  （实际上还是忽略所有值)
    let mut setting_value = Some(5);
    let new_setting_value = Some(10);
    match (setting_value, new_setting_value) {
        (Some(_), Some(_)) => {
            println!("Can't overwrite an existing customized value");
        }
        _ => {
            setting_value = new_setting_value;
        }
    }
    println!("setting is {setting_value:?}");


    // 10.1 这个匹配元组的稍微有点意思
    // 在rust，解构数据的部分为变量的时候，就意味着隐式定义了这样的一个变量
    // 例如下例中，n1,n3,n5 就是隐式定义的变量。后面的编码就尽量不要覆盖它们。

    // 根据这样的趋势，是不是rust让所有类型都可以模式匹配，例如数组
    let numbers = (2, 4, 8, 16, 32);
    match numbers {
        (n1, _, n3, _, n5) => {
            println!("Some numbers: {n1}, {n3}, {n5}")
        }
    }
    //10.2 数组的匹配
    let foods=["水","大米","萝卜","白菜"];
    match foods{
        [first,_,_,third]=>{
            println!("Some foods:{first},{third}");
        }
        _=>{}
    }
    //10.3 匹配向量  -- 这个好像不行
    // let books=vec!["诗经","春秋","论语"];
    // match books{
    //     [b1,b2,b3]=>{
    //         println!("Some books:{b1},{b2},{b3}");
    //     } 
    // }

    //11. 变量以下划线开头，以忽略不用警告 --  即一个下划线开头的变量，即使你没有使用，rustc也不会警告。否则会的
    // warning: unused variable: `sex`

    let  _sex="男";
    let  age=99;

    //12. 在匹配的时候，使用..跳过不想匹配的部分  。 这个作用和下划线有点类似，不过前者针对变量个数，后者针对具体变量的值范围
    match foods{
        [这是地瓜,..]=>{
            println!("第一格的食物是:{这是地瓜}");
        }       
    }

    // 三、条件 -----------------------------------------------------------------------
    //13.匹配守卫 -- 类似于if的条件判断 .不如称为匹配条件
    //利用匹配条件，可能会导致有些分支丢失的情况。但rustc不会报告异常，这个需要开发者自己注意。

    //13.1 条件中使用当前变量
    let x = Some(5);
    match  x {
       Some(z) if z>10=>{
           println!("Some(z) is greater than 10");
       }
       _=>{
           println!("Some(z)  小于等于 10");
       }
    }

    //13.2 条件中使用其它变量
    let x = 4;
    let y = false;

    match x {
        4 | 5 | 6 if y => println!("yes"),
        4 | 5 | 6 if !y => println!("no"),   //这一句如果不写，那么这个match会有丢失的分支
        _ => println!("其它情况"),
    }

    //14. @绑定， 是一个类似匹配套件的东西，只不过这个主要为枚举服务，且其表达式是比较简单，只能给一个范围?
    //有两种语法 val: val @ n..=m 或者 val @ n..m   .自然后面一种更加友好一些 

    let mywork=Work::Cancel(Color::OtherRgb(100,99,98));
    match mywork{
        Work::Cancel(Color::OtherRgb( r @99..104,g,b))=>{
            println!("r:{r},g:{g},b:{b}");
        },
        _=>{
            println!("其它情况");
        } 
    }

    match mywork{
        Work::Cancel(Color::OtherRgb( r @1..90,g,b))=>{
            println!("r:{r},g:{g},b:{b}");
        },
        _=>{
            println!("其它情况");
        } 
    }

}

fn ignore_test(_: i32, y: i32){
    println!("y:{y}");
    // 这个参数_无法访问。不知道rust搞这个有何意义
    //println!("忽略参数:{}",_);
}